package com.veepeak.server.service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.veepeak.server.common.BaseRepository;
import com.veepeak.server.common.BaseService;
import com.veepeak.server.common.DateUtils;
import com.veepeak.server.domain.*;
import com.veepeak.server.repository.DtcCommandLogRepository;
import com.veepeak.server.repository.DtcCommandRepository;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class DtcCommandLogService extends BaseService<DtcCommandLog,String> {
    @Autowired
    private DtcCommandLogRepository dtcCommandLogRepository;
    @Autowired
    private UserService userService;
    @Autowired
    private ObdService obdService;
    @Autowired
    private VehicleService vehicleService;

    @Override
    public BaseRepository<DtcCommandLog, String> getRepo() {
        return this.dtcCommandLogRepository;
    }

    public void saveDtcCommands(String userId, String obdId, String vehicleId,String faultTime, List<String> confirmPidList, List<String> pendingPidList) {
        User user = userService.get(userId);
        Obd obd = obdService.get(obdId);
        Vehicle vehicle = vehicleService.get(vehicleId);

        List<DtcCommandLog> logs = Lists.newArrayList();
        confirmPidList.forEach(pid -> {
            DtcCommandLog log = new DtcCommandLog(user,obd,vehicle);
            log.setCategory(DtcCommandLog.CATEGORY_DTC_CONFIRM);
            log.setSaveTime(DateUtils.getDateTime());
            log.setPid(pid);
            log.setFaultTime(faultTime);
            logs.add(log);
        });

        pendingPidList.forEach(pid -> {
            DtcCommandLog log = new DtcCommandLog(user,obd,vehicle);
            log.setCategory(DtcCommandLog.CATEGORY_DTC_PENDING);
            log.setSaveTime(DateUtils.getDateTime());
            log.setFaultTime(faultTime);
            log.setPid(pid);
            logs.add(log);
        });

        dtcCommandLogRepository.saveAll(logs);
    }

    public Map<String,List<JSONObject>> history(String userId, String obdId, String vehicleId, String startDate, String endDate) {
        Specification<DtcCommandLog> specification = new Specification<DtcCommandLog>() {
            @Override
            public Predicate toPredicate(Root<DtcCommandLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = Lists.newArrayList();
                predicates.add(criteriaBuilder.equal(root.get("user").get("id").as(String.class),userId));
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("faultTime").as(String.class),startDate));
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("faultTime").as(String.class),endDate));
                if (StringUtils.isNotBlank(obdId)){
                    predicates.add(criteriaBuilder.equal(root.get("obd").get("id").as(String.class),obdId));
                }
                if (StringUtils.isNotBlank(vehicleId)){
                    predicates.add(criteriaBuilder.equal(root.get("vehicle").get("id").as(String.class),vehicleId));
                }

                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };

        List<DtcCommandLog> historyLogs = dtcCommandLogRepository.findAll(specification);

        Map<String,List<JSONObject>> logs = Maps.newHashMap();

        for( DtcCommandLog log : historyLogs ){
            List<JSONObject> list = logs.get(log.getFaultTime());

            if ( list == null ){
                list = Lists.newArrayList();
                logs.put(log.getFaultTime(),list);
            }

            JSONObject result = new JSONObject();
            result.put("category",log.getCategory());
            result.put("faultTime",log.getFaultTime());
            result.put("id",log.getId());
            result.put("pid",log.getPid());
            result.put("remark",log.getRemark());
            result.put("userId",log.getUser().getId());
            result.put("obdId",log.getObd().getId());
            result.put("obdSn",log.getObd().getSerialsNumber());
            result.put("vehicleId",log.getVehicle().getId());
            result.put("vehicleLicenseNo",log.getVehicle().getLicenseNo());
            logs.get(log.getFaultTime()).add(result);
        }

        return logs;
    }
}
